#include "Setting.h"
#include "util.h"
#include <iostream>


void _Setting::Info()
{

	std::cout << "Available device:" << std::endl; 

	std::vector<cl::Device> devices;
	std::string dName, pName;

	for(int id = 0; id < _platforms.size(); id++)
	{
		_platforms[id].getInfo(CL_PLATFORM_NAME, &pName);
		std::cerr << "    " << pName << std::endl;
		_platforms[id].getDevices(CL_DEVICE_TYPE_ALL, &devices);
		for(int j = 0; j < devices.size(); j++){
			
			devices[j].getInfo(CL_DEVICE_NAME, &dName);
			int find = dName.find_first_not_of(' ');
			dName = dName.substr(find);
			std::cerr << "      -- " << dName << std::endl;
		}
	}
}

_Setting::_Setting(std::string platform, cl_device_type type)
{
	try
	{
		std::cerr << "Initialling OpenCL...\n";
		cl::Platform::get(&_platforms);

		Info();

		std::vector<cl::Device> devices;
		std::string name;
		bool found = false;
		cl_device_type devtype;

		for(unsigned id = 0; id < _platforms.size(); id++)
		{
			_platforms[id].getInfo(CL_PLATFORM_NAME, &name);
			_platforms[id].getDevices(CL_DEVICE_TYPE_ALL, &devices);
			if(name.find(platform) != std::string::npos)
			{
				for(unsigned did = 0; did < devices.size(); did++)
				{
					devices[did].getInfo(CL_DEVICE_TYPE, &devtype);
					if(devtype == type)
					{
						_platform = _platforms[id];
						_device = devices[did];
						found = true;
						break;
					}
				}

			}
		}

		if(!found)
		{
			_platforms[0].getDevices(CL_DEVICE_TYPE_DEFAULT, &devices);
			_platform = _platforms[0];
			_device = devices[0];
		}

		cl_context_properties prop[] = { CL_CONTEXT_PLATFORM, (cl_context_properties)_platform(), 0 };
		_context = cl::Context(CL_DEVICE_TYPE_ALL, prop);

		_queue = cl::CommandQueue(_context, _device, CL_QUEUE_PROFILING_ENABLE);

		_device.getInfo(CL_DEVICE_NAME, &name);
		int find = name.find_first_not_of(' ');
		name = name.substr(find);
		std::cerr << "Currently use " << name << '\n';
	}
	catch(cl::Error err)
	{
		std::cerr << "Error: " << err.what() << '(' << err.err() << ')' << '\n' ;
		std::cerr << "* " << oclErrorString(err.err()) << '\n';
	}

}


void _Setting::LoadProgram(std::string pName)
{
	std::cerr << "Load OpenCL kernel, \"" << pName << "\"\n";
	int size;
	const char* code = file_contents(pName.c_str(), &size);

	try
    {
        cl::Program::Sources source(1, std::make_pair(code, size));
        _program = cl::Program(_context, source);

		std::cerr <<"build program...\n";
		_program.build();

		std::cerr << "done building program\n";
    }
	catch (cl::Error err) {


		char log[65536];
		_program.getBuildInfo(_device, CL_PROGRAM_BUILD_LOG, &log);

		std::cerr << "Error: " << err.what() << '(' << err.err() << ')' << '\n' ;
		std::cerr << "* " << oclErrorString(err.err()) << '\n';
		std::cerr << log << std::endl;

		system("pause");
    }
}

